﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Arch.IoC;
using Microsoft.Practices.Unity;
using Arch.Data;
using System.Data.Objects;
using System.Data;
using Arch.Common.Reflection;
using Arch.EF.Data;
using System.ServiceModel.Activation;

namespace Arch.EF.Services
{
    public class EntityService<T> where T : class, new()
    {
        [Dependency]
        public virtual IRepository<T> Repository { get; set; }

        [Dependency]
        public virtual ObjectContext EntityContext { get; set; }

        public virtual T Load(int id)
        {
            var entity = Repository.Load(id);
            EntityContext.ContextOptions.LazyLoadingEnabled = false;
            return entity;
        }

        public virtual IEnumerable<T> FindAll()
        {
            var entities = Repository.Find();
            EntityContext.ContextOptions.LazyLoadingEnabled = false;
            return entities;
        }

        public virtual T Create(T entity)
        {
            Repository.Attach(entity);
            EntityContext.ObjectStateManager.ChangeObjectState(entity, EntityState.Added);
            var res = Repository.Create(entity);
            EntityContext.SaveChanges();

            EntityContext.ContextOptions.LazyLoadingEnabled = false;
            return res;
        }

        public virtual T Update(T entity)
        {
            var objectSet = EntityContext.CreateObjectSet<T>();

            T old = Repository.Load(entity.get(EntityContext.GetIdProperty<T>()));
            objectSet.ApplyCurrentValues(entity);

            foreach (var property in objectSet.EntitySet.ElementType.NavigationProperties)
            {
                object oldValue = old.get(property.Name);
                object newValue = entity.get(property.Name);

                if (!object.Equals(oldValue, newValue))
                {
                    if (newValue != null)
                    {
                        newValue = EntityContext.GetOriginal(EntityContext.GetEntitySet<T>().EntityContainer.Name + "." + property.ToEndMember.Name, newValue);
                    }
                    old.set(property.Name, newValue);
                }
            }

            var res = Repository.Update(entity);
            EntityContext.SaveChanges();

            EntityContext.ContextOptions.LazyLoadingEnabled = false;
            return res;
        }

        public virtual T Delete(T entity)
        {
            Repository.Attach(entity);
            var res = Repository.Delete(entity);
            EntityContext.SaveChanges();

            EntityContext.ContextOptions.LazyLoadingEnabled = false;
            return res;
        }
    }
}